package freaks.terah.model;

import java.util.Random;

import freaks.terah.gui.Gui;

public class AI {
	private EnvironmentModel envModel;
	private PlayerModel playerModel;
	private Gui parent;
	private int style;
	private Random rand;
	private int[] myExpenses = {0,0,0,0,0,0,0,0,0};
	
	
	public AI(Gui aParent, int playerNumber)
	{
		parent = aParent;
		envModel = null;
		playerModel = new PlayerModel(0,0,0,0);
		playerModel.setRole(1);
		playerModel.setPlayerNumber(playerNumber);
	}
	
	public void init(int AIStyle, int randomSeed) {
		style = AIStyle;
		rand = new Random(randomSeed);
		
		if (style == 0)
		{
			playerModel.setGoal(rand.nextInt(4) + 1);
			playerModel.setShip(rand.nextInt(4) + 1);
		}
	}
	
    public void setShip(int ship)
    {
    	playerModel.setShip(ship);
    }
    
    public void setGoal(int goal)
    {
    	playerModel.setGoal(goal);
    }
    
    public void setEnvironment(EnvironmentModel env)
    {
    	envModel = env;
    }
    
	public void doTurn()
	{
		int turn = parent.getTurn();
		playerModel.setCurrentAP(2);
		parent.addLogLine("Player " + parent.getPlayers().get(playerModel.getPlayerNumber()-1) + " plays turn " + turn + ".");
		parent.addLogLine("----------------------");

		playerModel.update();
		
		int struct = playerModel.getBuildableStructures().getSize();
		int tech = playerModel.getResearchTechs().getSize();

		for (int i = 0; i < struct;i++)
		{
			Structure s = (Structure) playerModel.getBuildableStructures().getElementAt(i);
			parent.addLogLine("Looking at " + s.getName());
			
			if (i == struct-1 && playerModel.canBuy(s))
			{
				playerModel.doAction(playerModel.ACTION_CREATE_STRUCTURE, i);
				
				for (int j = 0; j < 9;j++)
				{
					myExpenses[j] += s.getCost()[j];
				}
				
				if (playerModel.getPlayerNumber() == 3)
				    parent.addLogLine("Stealing " + s.getName());
				else
					parent.addLogLine("Buying " + s.getName());
			}
		}
		
		for (int i = 0; i < tech;i++)
		{
			Tech t = (Tech) playerModel.getResearchTechs().getElementAt(i);
			parent.addLogLine("Looking at " + t.getName());
			
			if (i == tech-1 && playerModel.canBuy(t))
			{
				playerModel.doAction(playerModel.ACTION_RESEARCH_TECH, i);
				
				for (int j = 0; j < 9;j++)
				{
					myExpenses[j] += t.getCost()[j];
				}
				
				if (playerModel.getPlayerNumber() == 3)
				    parent.addLogLine("Stealing " + t.getName());
				else
					parent.addLogLine("Researching " + t.getName());
			}
		}
		
		parent.addLogString("Ressources: ");
		for (int i = 0; i < 9; i++)
			parent.addLogString(playerModel.getPlayerRessources()[i] + " ");
		
		parent.addLogLine("");
		
		try {
			playerModel.setAllPlayerRessources(playerModel.getAllPlayerRessources(),0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (turn == 6)
			turn = 6;
		
		planUpkeep();
		playerModel.doPostTurn();
		
		if (turn > 100)
		{
			// Do something
		}
		
		//envModel.getPlanetData();
		
		parent.addLogLine("");
	}
	
	private void planUpkeep()
	{
	    long parents[][] = null;
		long data[][] = new long[100][2];
		
		// Init Vector
		for (int i = 0; i < 100; i++)
			data[i][0] = rand.nextLong();
		
		// Fitness
		for (int gen = 0; gen < 20; gen++)
		{
		    parents = calculateFitness(data);
		
		    for (int i = 0; i < 100; i++)
		    {
			    int a = rand.nextInt(20);
			    int b = rand.nextInt(20);
			    data[i][0] = (parents[a][0] & 0xAAAAAAAAAAAAAAAAL) + (parents[b][0] & 0x5555555555555555L);
		    }
		}
		
		RessourceModel structures = playerModel.getOwnedStructures();
		
		for (int j = 0; j < structures.getSize(); j++)
	    {
			boolean check = (parents[0][0] & (1L << j)) != 0 ? true : false;
			Structure r = (Structure) structures.get(j);
			r.setActive(check);
	    }
	}
	
	private long[][] calculateFitness(long[][] data)
	{
		long parents[][] = new long[20][2];
		
		for (int i = 0; i < 100; i++)
		{
			data[i][1] = fitnessFunction(data[i][0],playerModel);
		}
		
		int size = 0;
		
		for (int i = 0; i < 100; i++)
		{
			for (int j = 0; j < size;j++)
			{
				if (data[i][1] < parents[j][1])
				{
					long val = data[i][0];
					long fitness = data[i][1];
					for (int k = j;k < size;k++)
					{
						long sv = data[k][0];
						long sf = data[k][1];
						parents[k][0] = val;
						parents[k][1] = fitness;
						val = sv;
						fitness = sf;
					}
					
					if (size < 20)
					{
						parents[size][0] = val;
						parents[size][1] = fitness;
					    size++;
					}
				}
			}
		}
		
		return parents;
	}
	
	private long fitnessFunction(long data, PlayerModel playerModel)
	{
		int[] net = playerModel.getPlayerRessources().clone();
		RessourceModel structures = playerModel.getOwnedStructures();
		for (int j = 0; j < structures.getSize(); j++)
	    {
			if ((data & (1L << j)) != 0)
			{
				Ressource r = (Ressource) structures.get(j);
				
				for (int k = 0; k < 9; k++)
					net[k] += r.getOutput()[k] - r.getUpkeep()[k];
			}
	    }
		
		int pos = 0;
		int neg = 0;
		for (int k = 0; k < 9; k++)
		{
			if (net[k] > 0)
			{
				pos += net[k];
			}
			
			if  (net[k] < 0)
			{
				neg -= net[k];
			}
		}
	    
		return (neg << 10) + (999-pos);
	}
}
